{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0",
   "metadata": {},
   "source": [
    "# Schematic\n",
    "\n",
    "A schematic is a graph representation of your circuit.\n",
    "\n",
    "For complex circuits, a schematic allows you to create symbols and hierarchy levels to represent your circuit.\n",
    "\n",
    "Having a schematic allows you to also ensure that your layout matches you schematic (design intent).\n",
    "\n",
    "There are many schematic capturing tools out there:\n",
    "\n",
    "- Qucs-s: for RF.\n",
    "- Xschem: for analog circuits.\n",
    "- Lumerical interconnect: for photonic circuits.\n",
    "\n",
    "These tools allow you to create schematics with either your mouse or by code.\n",
    "\n",
    "gdsfactory also allows you to create complex Schematics directly from python with a very simple interface."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import gdsfactory as gf\n",
    "import yaml\n",
    "from functools import partial"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2",
   "metadata": {},
   "outputs": [],
   "source": [
    "@gf.schematic_cell\n",
    "def my_schematic(x: float = 108.5, y: float = 53.1) -> gf.Schematic:\n",
    "    \"\"\"Returns a schematic with two rings connected by a waveguide.\"\"\"\n",
    "    s = gf.Schematic()\n",
    "    r1 = s.create_inst(name=\"r1\", component=\"ring_single\")\n",
    "    r1.place(x=0, y=0)\n",
    "\n",
    "    r2 = s.create_inst(name=\"r2\", component=\"ring_single\", settings={\"radius\": 32.2})\n",
    "    r2.place(x=x, y=y)\n",
    "\n",
    "    s.add_route(\n",
    "        name=\"r1-r2\",\n",
    "        start_ports=[r1.ports[\"o2\"]],\n",
    "        end_ports=[r2.ports[\"o1\"]],\n",
    "        routing_strategy=\"route_bundle\",\n",
    "    )\n",
    "    return s\n",
    "\n",
    "c = my_schematic()\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3",
   "metadata": {},
   "outputs": [],
   "source": [
    "@gf.schematic_cell(\n",
    "    factories=gf.get_factories.get_cells(\"gdsfactory\"),\n",
    "    routing_strategies=gf.get_active_pdk().routing_strategies\n",
    "    or {\n",
    "        \"route_bundle\": partial(\n",
    "            gf.routing.route_bundle, layer=gf.get_layer((1, 0)), route_width=1\n",
    "        )\n",
    "    },\n",
    ")\n",
    "def my_schematic(x: float = 108.5, y: float = 53.1) -> gf.Schematic:\n",
    "    \"\"\"Returns a schematic with two rings connected by a waveguide.\"\"\"\n",
    "    s = gf.Schematic()\n",
    "    r1 = s.create_inst(name=\"r1\", component=\"ring_single\")\n",
    "    r1.place(x=0, y=0)\n",
    "\n",
    "    r2 = s.create_inst(name=\"r2\", component=\"ring_single\", settings={\"radius\": 32.2})\n",
    "    r2.place(x=x, y=y)\n",
    "\n",
    "    s.add_route(\n",
    "        name=\"r1-r2\",\n",
    "        start_ports=[r1.ports[\"o2\"]],\n",
    "        end_ports=[r2.ports[\"o1\"]],\n",
    "        routing_strategy=\"route_bundle\",\n",
    "    )\n",
    "\n",
    "    return s\n",
    "\n",
    "c = my_schematic()\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4",
   "metadata": {},
   "outputs": [],
   "source": [
    "@gf.schematic_cell\n",
    "def ring_array(n: int = 3, pitch_x: float = 100, pitch_y=50, radius: float = 10, radius_delta: float = 5) -> gf.Schematic:\n",
    "    \"\"\"Returns a schematic with n rings connected by a waveguide.\"\"\"\n",
    "    s = gf.Schematic()\n",
    "\n",
    "    last_ring  = None\n",
    "\n",
    "    for i in range(n):\n",
    "        r = s.create_inst(name=f\"r{i}\", component=\"ring_single\", settings={\"radius\": radius+i*radius_delta})\n",
    "        r.place(x=i*pitch_x, y=i*pitch_y)\n",
    "        if last_ring is not None:\n",
    "            s.add_route(\n",
    "                name=f\"r{i-1}-r{i}\",\n",
    "                start_ports=[last_ring.ports[\"o2\"]],\n",
    "                end_ports=[r.ports[\"o1\"]],\n",
    "                routing_strategy=\"route_bundle\",\n",
    "            )\n",
    "        last_ring = r\n",
    "    return s\n",
    "\n",
    "c = ring_array()\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.c.mzi()\n",
    "\n",
    "# .plot_netlist_graphviz(): This method reads the component's netlist and uses Graphviz (a graph visualization tool) to create a block diagram.\n",
    "# interactive=False: This parameter specifies that the output should be a static image rather than an interactive plot.\n",
    "c.plot_netlist_graphviz(interactive=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6",
   "metadata": {},
   "outputs": [],
   "source": [
    "c.plot_netlist()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7",
   "metadata": {},
   "source": [
    "Lets create a MZI lattice of 3 elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from kfactory.schematic import RegularArray\n",
    "import gdsfactory as gf\n",
    "\n",
    "@gf.cell\n",
    "def splitter_tree_with_new_ports(**kwargs) -> gf.Component:\n",
    "    \"\"\"Returns a splitter tree with new ports.\"\"\"\n",
    "    c = gf.c.splitter_tree(**kwargs).copy()\n",
    "    c.auto_rename_ports()\n",
    "    return c\n",
    "\n",
    "\n",
    "pdk = gf.get_active_pdk()\n",
    "pdk.register_cells(splitter_tree_new_ports=splitter_tree_with_new_ports)\n",
    "\n",
    "\n",
    "@gf.schematic_cell(overwrite_existing=True) # for development \n",
    "def lidar(n: int = 2**3, dbr_pitch: float = 3) -> gf.Schematic:\n",
    "    \"\"\"Returns a schematic with lidar array by a waveguide.\"\"\"\n",
    "    s = gf.Schematic()\n",
    "    spt = s.create_inst(name=\"splitter\", component='splitter_tree_new_ports', settings={'noutputs': n, 'spacing': (50, 50)})\n",
    "    dbr = s.create_inst(name=\"dbr\", component='dbr', array=RegularArray(rows=n, column_pitch=0, row_pitch=dbr_pitch))\n",
    "    spt.place(x=0, y=0)\n",
    "    dbr.place(x=250+n*dbr_pitch, y=-n*dbr_pitch/2+dbr_pitch/2)\n",
    "\n",
    "    start_ports = [spt.ports[f\"o{i+2}\"] for i in range(n)]\n",
    "    end_ports = [dbr.ports[\"o1\", 0, i] for i in range(n)]\n",
    "\n",
    "    s.add_route(\n",
    "            name=\"splitter_to_dbr\",\n",
    "            start_ports=start_ports,\n",
    "            end_ports=end_ports,\n",
    "            routing_strategy=\"route_bundle\",\n",
    "            radius=5,\n",
    "            separation=3,\n",
    "            sort_ports=True,\n",
    "        )\n",
    "    return s\n",
    "\n",
    "c = lidar(n=2**4)\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "custom_cell_magics": "kql",
   "encoding": "# -*- coding: utf-8 -*-"
  },
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
